﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StyleMVVM.Data;
using StyleMVVM.Data.Collections;
using StyleMVVM.Utilities;
#if !DOT_NET
using Windows.Foundation.Collections;

#endif

namespace StyleMVVM.ViewModel
{
	/// <summary>
	/// Represents a ViewModel that wraps a data value of type T.
	/// It automatically tracks edits and can rollback or commit to the value
	/// DataBinding should go directly against this data context not the Value object
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class EditableDataViewModel<T> : BaseViewModel, IEditableDataWrapper<T> where T : class
	{
		protected IEditableDataWrapper<T> editWrapper;

		public EditableDataViewModel()
		{
			editWrapper = new EditableDataWrapper<T>();

			editWrapper.MapChanged += editWrapperMapChanged;
			editWrapper.PropertyChanged += editWrapperPropertyChanged;
		}

		#region IEditableDataWrapper

		public T Value
		{
			get { return editWrapper.Value; }
			set { editWrapper.Value = value; }
		}

		public bool PendingChanges
		{
			get { return editWrapper.PendingChanges; }
		}

		public EditingMode EditingMode
		{
			get { return editWrapper.EditingMode; }
			set { editWrapper.EditingMode = value; }
		}

		public void Commit()
		{
			editWrapper.Commit();
		}

		public void RollBack()
		{
			editWrapper.RollBack();
		}

		public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
		{
			return editWrapper.GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return GetEnumerator();
		}

		public void Add(KeyValuePair<string, object> item)
		{
			editWrapper.Add(item);
		}

		public void Clear()
		{
			editWrapper.Clear();
		}

		public bool Contains(KeyValuePair<string, object> item)
		{
			return editWrapper.Contains(item);
		}

		public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
		{
			editWrapper.CopyTo(array, arrayIndex);
		}

		public bool Remove(KeyValuePair<string, object> item)
		{
			return editWrapper.Remove(item);
		}

		public int Count
		{
			get { return editWrapper.Count; }
		}

		public bool IsReadOnly
		{
			get { return editWrapper.IsReadOnly; }
		}

		public void Add(string key, object value)
		{
			editWrapper.Add(key, value);
		}

		public bool ContainsKey(string key)
		{
			return editWrapper.ContainsKey(key);
		}

		public bool Remove(string key)
		{
			return editWrapper.Remove(key);
		}

		public bool TryGetValue(string key, out object value)
		{
			return editWrapper.TryGetValue(key, out value);
		}

		public object this[string key]
		{
			get { return editWrapper[key]; }
			set { editWrapper[key] = value; }
		}

		public ICollection<string> Keys
		{
			get { return editWrapper.Keys; }
		}

		public ICollection<object> Values
		{
			get { return editWrapper.Values; }
		}

		public event MapChangedEventHandler<string, object> MapChanged;

		protected void RaiseMapChanged(string key,
		                               CollectionChange change = CollectionChange.ItemChanged)
		{
			if (MapChanged != null)
			{
#if NETFX_CORE
				MapChanged(this,
				           new ObservableDictionaryChangedEventArgs<string>(CollectionChange.ItemChanged, key));
#else
	// TODO
#endif
			}
		}

		private void editWrapperPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			OnPropertyChanged(e.PropertyName);
		}

		private void editWrapperMapChanged(IObservableMap<string, object> sender, IMapChangedEventArgs<string> @event)
		{
			if (MapChanged != null)
			{
				MapChanged(this, @event);
			}
		}

		#endregion
	}
}